iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0

摘要
Day 17 已經把契約 v1.0 / v1.1 的差異轉成可修正的證據。Day 18 把目前的資料品質閘門放進可重現的執行環境:新增 Dockerfile、Docker Compose 與 GitHub Actions,讓同一套 Maven test / package 流程可以在本機容器與 CI 上執行。

這和「能不能交換」有什麼關係?

前面幾天已經可以回答:

這份 Bundle 在 JSON、FHIR R4、TW Core 與交換契約規則下能不能通過?

但如果這個答案只存在於我自己的電腦上,仍然不夠。
資料品質閘門要能支撐交換情境,至少還要回答另一個問題:

換一台乾淨環境,驗證結果還能不能重現?

這件事不只是部署問題。
它會影響測試證據的可信度。
如果本機可以跑、別人的環境不能跑,或 CI 沒有固定執行測試,那前面建立的規則、Expected / Actual 與版本比較,都很難被當成穩定成果。

所以 Day 18 的重點是:

把目前的驗證流程包成可建置、可啟動、可由 CI 檢查的最小交付單位。

今天的實作範圍

今天新增或修改的範圍有:

  • Dockerfile
  • .dockerignore
  • docker-compose.yml
  • .github/workflows/ci.yml
  • README.md
  • 20260819.md

目前六條規則、Quality Gate 與契約比較都已經完成最小版。
所以下一步補上 Docker 與 CI quality gate。

Dockerfile:用 multi-stage build 包 Spring Boot

新增的 Dockerfile 採用兩階段:

FROM eclipse-temurin:17-jdk AS build

第一階段使用 JDK 建置專案。
專案目前 pom.xml 設定的是:

<java.version>17</java.version>

所以 Docker 和 CI 都先固定使用 Java 17。
Docker build 先複製 Maven wrapper 與 pom.xml

COPY .mvn .mvn
COPY mvnw pom.xml ./
RUN chmod +x mvnw
RUN ./mvnw -q -DskipTests dependency:go-offline

這樣做的目的,是讓 Maven dependency 下載可以被 Docker layer cache 重用。
後續如果只改 Java 或 template,Docker 不一定要從頭下載全部 Maven dependency。

接著複製原始碼並打包:

COPY src src
RUN ./mvnw -q package

第二階段改用 JRE:

FROM eclipse-temurin:17-jre

只把 Spring Boot repackaged jar 複製到 runtime image:

COPY --from=build /workspace/target/twcore-data-quality-gate-0.0.1-SNAPSHOT.jar app.jar

最後開放 8080 並啟動:

EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

.dockerignore:不把不必要的檔案送進 build context

容器建置時,Docker 會先把 build context 傳給 daemon。
如果沒有 .dockerignore,可能會把 .gittarget、log 或其他本機檔案一起送進去。

這次先排除:

.git
.github
.mvn/wrapper/maven-wrapper.jar
target
*.log
.DS_Store
HELP.md

target 一定要排除。
Docker image 必須在容器裡自己跑 Maven build,不能偷偷依賴本機已經打好的 jar。
這樣才能驗證:

乾淨環境真的能從原始碼建出可執行應用程式。

Docker Compose:固定本機啟動方式

新增的 docker-compose.yml 很小:

services:
  twcore-data-quality-gate:
    build: .
    ports:
      - "8080:8080"

目前 MVP 沒有資料庫,也沒有 queue、cache 或外部 service。
所以 Compose 只需要一個 service。
這樣使用者只要執行:

docker compose up --build

就能啟動整套 Spring Boot 應用程式。

啟動後開:

http://localhost:8080

https://ithelp.ithome.com.tw/upload/images/20260819/20177913JIPAQLgxZL.png

確認容器真的跑起來

Compose 啟動後,用:

docker compose ps

可以看到:

twcore-data-quality-gate-1   Up   0.0.0.0:8080->8080/tcp

再用 curl 檢查首頁:

curl -s -o /tmp/twcore-home.html -w '%{http_code}' http://localhost:8080

回傳:

200

並確認 HTML 裡包含:

TW Lab Contract Gate

這表示不是只有 container 處於 running 狀態,而是 Spring Boot app 真的有對外回應。
容器 log 也確認 runtime 使用 Java 17:

Starting TwcoreDataQualityGateApplication v0.0.1-SNAPSHOT using Java 17.0.19
Tomcat started on port 8080

https://ithelp.ithome.com.tw/upload/images/20260819/20177913NASsD6dtwR.png

GitHub Actions:把 Maven test / package 放進 CI

Day 18 也新增:

.github/workflows/ci.yml

讓 CI 保護「59 個規則/Controller/情境比較測試」

workflow 觸發條件是:

on:
  push:
  pull_request:

也就是 push 和 pull request 都會跑。
使用 GitHub-hosted runner:

runs-on: ubuntu-latest

Java 設定固定為 Temurin 17:

- name: Set up Java
  uses: actions/setup-java@v4
  with:
    distribution: temurin
    java-version: "17"
    cache: maven

然後執行兩個步驟:

- name: Run tests
  run: ./mvnw test

- name: Build package
  run: ./mvnw package

https://ithelp.ithome.com.tw/upload/images/20260819/20177913RIyTA08eG7.png

這裡刻意不在第一版 CI 加入 Docker build。
原因是今天的 minimum quality gate 先鎖定:

Maven test 必須通過。
Spring Boot package 必須能建出 jar。

之後如果要再提高 CI 門檻,可以另外補上 Docker image build。

自動化驗證

本機 Maven 測試:

./mvnw test

結果:

Tests run: 59, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

https://ithelp.ithome.com.tw/upload/images/20260819/20177913E7bak1xEbo.png

本機 Maven package:

./mvnw package

結果:

BUILD SUCCESS

Docker Compose:

docker compose up --build

結果:

Image twcore-data-quality-gate-twcore-data-quality-gate Built
Container twcore-data-quality-gate-twcore-data-quality-gate-1 Started

HTTP 驗證:

HTTP 200 / homepage contains TW Lab Contract Gate

目前 Docker image 大小約:

493MB

常見錯誤 & 排查

  1. Docker CLI 裝好了,但 daemon 沒有啟動

如果執行:

docker info

看到類似:

failed to connect to the docker API

通常代表 Docker Desktop 還沒啟動完成。
這時要先開 Docker Desktop,等 daemon ready,再重跑 Docker 指令。

  1. macOS 阻擋 com.docker.vmnetd

如果 macOS 顯示 com.docker.vmnetd 被阻擋,不硬開未知來源。
這次處理方式是重新安裝 Docker Desktop,讓 Docker daemon 正常啟動後再驗證。

  1. 8080 已經被本機 process 佔用

錯誤訊息:

bind: address already in use

排查:

lsof -nP -iTCP:8080 -sTCP:LISTEN

如果是舊的本機 Spring Boot app,停止它後再跑:

docker compose up -d
  1. 不要把本機 target 放進 Docker image

如果 .dockerignore 沒有排除 target,Docker build 可能會意外吃到本機舊產物。
這會讓「乾淨環境可重建」的證據變弱。
所以 Day 18 明確把 target 排除,讓 image 必須自己從原始碼 build。

今天完成了什麼

  • 新增 Java 17 multi-stage Dockerfile
  • 新增 .dockerignore
  • 新增單 service docker-compose.yml
  • 新增 GitHub Actions CI workflow。
  • README 補上 Docker Compose 與 CI 說明。
  • ./mvnw test 通過,測試數 59。
  • ./mvnw package 通過。
  • docker compose up --build 成功建 image。
  • docker compose up -d 成功啟動 container。
  • http://localhost:8080 回傳 HTTP 200。
  • 確認 container runtime 使用 Java 17。

Day 18 尚未處理:

  • GitHub Actions 實際遠端執行結果截圖。
  • CI 裡執行 Docker image build。
  • Docker image size 最佳化。
  • Docker healthcheck。
  • README 完整架構圖與 Demo 劇本。
  • 簡化歷史紀錄。
  • Change Manifest、三分類、JSON Diff。

目前的 MVP 進度:

validation-flow
├─ JSON parse                                  完成
├─ FHIR R4 parse                               完成
├─ FHIR R4 validation                          完成
├─ TW Core validation / safe NOT_EVALUATED      完成
├─ Exchange contract rules
│  ├─ LAB-REF-001                              完成並接回畫面
│  ├─ LAB-REF-002                              完成並接回畫面
│  ├─ LAB-REF-003                              完成並接回畫面
│  ├─ LAB-CODE-001                             完成並接回畫面
│  ├─ LAB-UNIT-001                             完成並接回畫面
│  └─ LAB-UNIT-002                             完成並接回畫面
├─ Quality Gate                                完成最小版
├─ Contract comparison
│  ├─ ContractVersion                          完成最小版
│  ├─ v1.0 / v1.1 rule selection                完成最小版
│  ├─ comparison service test                   完成最小版
│  ├─ homepage comparison display               完成最小版
│  └─ upgrade blocker evidence display          完成最小版
├─ Scenario test pack
│  ├─ minimal expected / actual table           完成最小版
│  ├─ v1.0 / v1.1 representative cases          完成 4 例
│  └─ NOT_APPLICABLE scenario fixture           完成 1 例
└─ Reproducible delivery
   ├─ Dockerfile                                完成最小版
   ├─ Docker Compose                            完成最小版並驗證啟動
   └─ GitHub Actions CI                         完成最小版

下一步預計處理:

GitHub Actions 遠端綠燈確認
README 支援範圍與限制整理

Repository:twcore-data-quality-gate


上一篇
Day17 - 把版本差異變成可解讀的修正證據
下一篇
Day19 - 驗證覆蓋證據與整理 Quality Test Report
系列文
醫療資料通過標準驗證,就真的能交換嗎?——30 天打造 TW Core 資料品質閘門21
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言